import logging
import os
import subprocess
import sys
import time
import traceback
import zipfile
from datetime import datetime

import oss2
import prettytable
import rarfile as rarfile
import requests


from automonkey.config import DefaultConfig
from automonkey.exception import FileDownloadErrorException

logger = logging.getLogger(__name__)

"""
#  工具类
"""


class Utils(object):

    @classmethod
    def command_execute(cls, cmd,timeout=10):
        # try:
        if not cmd:
            return False
        logger.info(cmd)
        command_process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
                                            executable="/bin/bash")

        return cls.process_listener(command_process,timeout)
        # except Exception as e:
        #     logger.error( '{}, {}'.format(e,cmd))
        #     traceback.print_exc()

    @classmethod
    def bug_report_tool(cls, log_path):
        try:
            if not os.path.exists(log_path):
                return None
            local_path = os.getcwd()
            chk_path = os.path.abspath(os.path.join(local_path, "./tools/check_bug_report/chkbugreport"))
            jar_path = os.path.abspath(os.path.join(local_path, "./tools/check_bug_report"))

            if not os.path.exists(chk_path):
                logger.error('tool path not found at {}'.format(chk_path))
                return None

            os.system('chmod +x {}'.format(chk_path))

            cmd = '{} {} {}'.format(chk_path, log_path, jar_path)
            p = cls.command_execute(cmd,timeout=300)
            return p.stdout.readlines()
        except Exception as e:
            logger.error(e)
            logger.error(traceback.format_exc())

    @classmethod
    def show_info_as_table(cls, keys, values):
        # keys list; values list(dict) or dict
        table = prettytable.PrettyTable()
        if isinstance(values, list):
            table.field_names = keys
            for v in values:
                if isinstance(v, list):
                    row = v
                elif isinstance(v, dict):
                    row = v.values()
                table.add_row(row)
        elif isinstance(values, dict):
            table.field_names = ['key', 'value']
            for v in keys:
                row = [v, values.get(v)]
                table.add_row(row)
        logger.info('\n{}'.format(table))

    # 下载 apk 文件
    @classmethod
    def download_apk_from_url(cls, url, target_path, target_name):
        try:
            if not os.path.exists(target_path):
                os.mkdir(target_path)
            if target_name is None:
                date_time_now = datetime.now().strftime('%Y%m%d-%H.%M.%S')
                target_name = '{}.apk'.format(date_time_now)
            elif not target_name.endswith('.apk'):
                target_name = '{}.apk'.format(target_name)

            download_apk_name = os.path.join(target_path, target_name)

            logger.info('开始从 {} 下载到 {}'.format(url, download_apk_name))

            response = requests.get(url=url, verify=False)

            with open(download_apk_name, 'wb') as f:
                f.write(response.content)

            # 下载失败
            if not os.path.exists(download_apk_name):
                logger.error('{} 下载失败!'.format(url))
                raise FileDownloadErrorException

            logger.info('下载成功,保存地址 {}'.format(download_apk_name))

            return download_apk_name
        except Exception as e:
            print(e)
            traceback.print_exc()
            raise e

    @classmethod
    def upload_bug_report_log_to_oss(cls, log_path):
        endpoint = DefaultConfig.OSS_URL
        auth = DefaultConfig.OSS_AUTH
        bucket = oss2.Bucket(auth, endpoint, DefaultConfig.OSS_BUCKET_NAME)
        cls.upload_dir(log_path, bucket)

    @classmethod
    def upload_file_to_oss(cls, local_path, bucket=None):
        if not bucket:
            endpoint = DefaultConfig.OSS_URL
            auth = DefaultConfig.OSS_AUTH
            bucket = oss2.Bucket(auth, endpoint, DefaultConfig.OSS_BUCKET_NAME)

        now = datetime.now().strftime("%Y-%m-%d")
        build_number = os.environ.get('BUILD_NUMBER')
        remote_file_path = 'monkey/{}/{}/{}'.format(now, build_number, local_path)
        bucket.put_object_from_file('{}'.format(remote_file_path), local_path)

    @classmethod
    def upload_dir(cls, dir_path, bucket):
        if not bucket:
            endpoint = DefaultConfig.OSS_URL
            auth = DefaultConfig.OSS_AUTH
            bucket = oss2.Bucket(auth, endpoint, DefaultConfig.OSS_BUCKET_NAME)

        fs = os.listdir(dir_path)
        dir_path_new = dir_path
        for f in fs:
            file = dir_path_new + "/" + f
            if os.path.isdir(file):
                cls.upload_dir(file, bucket)
            else:
                if 'DS_Store' not in file:
                    print(file)
                    cls.upload_file_to_oss(file, bucket)

    @classmethod
    def deal_with_python_version(cls, data):
        if str(sys.version_info.major) == '3':
            if isinstance(data, list):
                return [d.decode('utf-8') for d in data]
            else:
                return data.decode('utf-8')
        else:
            return data

    @classmethod
    def unpack_zip(cls, file, folder):
        zip_file = zipfile.ZipFile(file)
        zip_file.extractall(path=folder)
        zip_file.close()

    @classmethod
    def unpack_rar(cls, file, folder):
        rar_file = rarfile.RarFile(file)
        rar_file.extractall(folder)
        rar_file.close()

    @classmethod
    def process_listener(cls, process, timeout=15):
        start = datetime.now()
        while process.poll() is None:
            time.sleep(0.5)
            now = datetime.now()
            if (now - start).seconds > timeout:
                process.kill()
                logger.error("adb request timeout")
                # raise IOError("adb request timeout")
        return process